iT邦幫忙

2024 iThome 鐵人賽

DAY 23
0
佛心分享-SideProject30

門外漢的嵌入式地獄系列 第 23

Day 23 。初入嵌入式開發- 如何修改 BSP - Uboot 篇

  • 分享至 

  • xImage
  •  

在 Uboot 當中,一樣要去修改 DDR Size , 避免在Uboot 當中會出現認錯位置的情況。其餘的也是依照不同的開發板,或是你想要的不同功能來去做修改。例如你可能希望在這個階段,你要使用到RMII的功能,那就必須要在Uboot 的設備樹當中正確地去設定。

下載 Uboot 的 Source code

devtool modify u-boot-stm32mp

Uboot 流程分析

這部分是粗略的說明,主要其實我們只需要理解大致上的邏輯,不會真的需要去修改到他

其實當我們進到 uboot 當中 , 也有非常多指令可以使用 。
例如 mmc list 可以用來查看 emmc , print env 可以列出環境變數。

uboot bootcmd環境變數儲存了 uboot預設的指令, 啟動時會看到讀秒(大約一秒的時間,這時候按下 enter 就會進到 uboot) ,uboot倒數結束後就會執行bootcmd中的命令。下方是 bootcmd啟動linux的流程:

altbootcmd=run bootcmd
arch=arm
autoload=no
baudrate=115200
board=stm32mp1
board_name=stm32mp157d-robot
boot_a_script=load ${devtype} ${devnum}:${distro_bootpart} ${scriptaddr} ${prefix}${script}; source ${scriptaddr}
boot_device=mmc
boot_efi_binary=
	if fdt addr ${fdt_addr_r}; then 
		bootefi bootmgr ${fdt_addr_r};
	else 
		bootefi bootmgr ${fdtcontroladdr};
	fi;
	load ${devtype} ${devnum}:${distro_bootpart} ${kernel_addr_r} efi/boot/bootarm.efi; 
	if fdt addr ${fdt_addr_r}; then 
		bootefi ${kernel_addr_r} ${fdt_addr_r};
	else 
		bootefi ${kernel_addr_r} ${fdtcontroladdr};
	fi
boot_extlinux=sysboot ${devtype} ${devnum}:${distro_bootpart} any ${scriptaddr} ${prefix}${boot_syslinux_conf}
boot_instance=0
boot_m4fw=rproc init; rproc load 0 ${m4fw_addr} ${filesize}; rproc start 0
boot_net_usb_start=true
boot_prefixes=/ /boot/
boot_script_dhcp=boot.scr.uimg
boot_scripts=boot.scr.uimg boot.scr
boot_syslinux_conf=extlinux/extlinux.conf
boot_targets=mmc1 ubifs0 mmc0 mmc2 pxe 
bootcmd=run bootcmd_stm32mp
bootcmd_mmc0=devnum=0; run mmc_boot
bootcmd_mmc1=devnum=1; run mmc_boot
bootcmd_mmc2=devnum=2; run mmc_boot
bootcmd_pxe=run boot_net_usb_start; dhcp; if pxe get; then pxe boot; fi
bootcmd_stm32mp=
	echo "Boot over ${boot_device}${boot_instance}!";
	if test ${boot_device} = serial || test ${boot_device} = usb;then 
		stm32prog ${boot_device} ${boot_instance}; 
	else 
		run env_check;
		if test ${boot_device} = mmc;then 
			env set boot_targets "mmc${boot_instance}"; 
		fi;
		if test  ${boot_device} = nand || test ${boot_device} = spi-nand ;then 
			env set boot_targets ubifs0; 
		fi;
		if test ${boot_device} = nor;then 
			env set boot_targets mmc0; 
		fi;
		run distro_bootcmd;
	fi;
bootcmd_ubifs0=devnum=0; run ubifs_boot
bootcount=4
bootdelay=1
bootfstype=ext4
cpu=armv7
distro_bootcmd=
	for target in ${boot_targets}; 
	do 
		run bootcmd_${target}; 
	done
efi_dtb_prefixes=/ /dtb/ /dtb/current/
env_check=if env info -p -d -q; then env save; fi
fdt_addr_r=0xc4000000
fdtcontroladdr=f3ae4d20
fdtfile=stm32mp157d-robot.dtb
fdtoverlay_addr_r=0xc4100000
fileaddr=c4100000
filesize=b7f
kernel_addr_r=0xc2000000
load_efi_dtb=load ${devtype} ${devnum}:${distro_bootpart} ${fdt_addr_r} ${prefix}${efi_fdtfile}
loadaddr=0xc2000000
m4fw_addr=0xc2000000
m4fw_name=rproc-m4-fw.elf
mmc_boot=
	if mmc dev ${devnum}; then 
		devtype=mmc; 
		run scan_dev_for_boot_part; 
	fi
pxefile_addr_r=0xc4200000
ramdisk_addr_r=0xc4400000
scan_dev_for_boot=
	echo Scanning ${devtype} ${devnum}:${distro_bootpart}...; 
	for prefix in ${boot_prefixes}; 
	do 
		run scan_dev_for_extlinux; 
		run scan_dev_for_scripts; 
	done;
	run scan_dev_for_efi;
scan_dev_for_boot_part=
	part list ${devtype} ${devnum} -bootable devplist; 
	env exists devplist || setenv devplist 1; 
	for distro_bootpart in ${devplist}; 
	do 
		if fstype ${devtype} ${devnum}:${distro_bootpart} bootfstype; then 
			run scan_dev_for_boot; 
		fi; 
	done; 
	setenv devplist
scan_dev_for_efi=
	setenv efi_fdtfile ${fdtfile}; 
	if test -z "${fdtfile}" -a -n "${soc}"; then 
		setenv efi_fdtfile ${soc}-${board}${boardver}.dtb; 
	fi; 
	for prefix in ${efi_dtb_prefixes}; 
	do 
		if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${efi_fdtfile}; then 
			run load_efi_dtb; 
		fi;
	done;
	if test -e ${devtype} ${devnum}:${distro_bootpart} efi/boot/bootarm.efi; then 
		echo Found EFI removable media binary efi/boot/bootarm.efi; 
		run boot_efi_binary; echo EFI LOAD FAILED: continuing...; 
	fi; 
	setenv efi_fdtfile
scan_dev_for_extlinux=
	if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${boot_syslinux_conf}; then 
		echo Found ${prefix}${boot_syslinux_conf}; 
		run boot_extlinux; 
		echo SCRIPT FAILED: continuing...; 
	fi
scan_dev_for_scripts=
	for script in ${boot_scripts}; 
	do 
		if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${script}; then 
			echo Found U-Boot script ${prefix}${script}; 
			run boot_a_script; 
			echo SCRIPT FAILED: continuing...; 
		fi; 
	done
scan_m4fw=
	if test -e ${devtype} ${devnum}:${distro_bootpart} ${m4fw_name};then 
		echo Found M4 FW $m4fw_name; 
		if load ${devtype} ${devnum}:${distro_bootpart} ${m4fw_addr} ${m4fw_name}; then 
			run boot_m4fw; 
		fi; 
	fi;
scriptaddr=0xc4100000
serial#=003A002B3030511039383538
serverip=192.168.1.1
soc=stm32mp
splashimage=0xc4300000
ubifs_boot=
	env exists bootubipart || env set bootubipart UBI; 
	env exists bootubivol || env set bootubivol boot; 
	if ubi part ${bootubipart} && ubifsmount ubi${devnum}:${bootubivol}; then 
		devtype=ubi; 
		run scan_dev_for_boot; 
	fi
usb_boot=
	usb start; 
	if usb dev ${devnum}; then 
		devtype=usb; 
		run scan_dev_for_boot_part; 
	fi
vendor=st

Environment size: 4413/8187 bytes

bootcmd

bootcmd=run bootcmd_stm32mp
bootcmd_stm32mp=
	echo "Boot over ${boot_device}${boot_instance}!";     #  ${boot_device}${boot_instance}: mmc0(sdcard 啟動,通常 mmc0 都會是 SD)
	run env_check;
	if test ${boot_device} = mmc;then 
		env set boot_targets "mmc${boot_instance}";            boot_targets mmc0
	fi;
	run distro_bootcmd;

distro_bootcmd=
	for target in ${boot_targets}; 
	do 
		run bootcmd_${target};                                                        # run bootcmd_mmc0
	done

bootcmd_mmc0=
	devnum=0;                                                                                    # devnum=0
	run mmc_boot
	
mmc_boot=
	if mmc dev ${devnum}; then 
		devtype=mmc;                                                                         # devtype=mmc
		run scan_dev_for_boot_part; 
	fi

下方的 scan_dev_for_boot_part 函數就是去檢查mmc0的分區裡面是否有bootfs的分區lable,如果有找到對應的label,就對應上面的4分區,然後會去執行scan_dev_for_boot

scan_dev_for_boot_part=
	part list ${devtype} ${devnum} -bootable devplist;  #查看 SD的 boot 分區就是 mmc0
	env exists devplist || setenv devplist 1; 
	for distro_bootpart in ${devplist}; 
	do 
		if fstype ${devtype} ${devnum}:${distro_bootpart} bootfstype; then 
			run scan_dev_for_boot; 
		fi; 
	done; 
	setenv devplist

下方的函數是去找SD卡boot分割區裡面/ (根目錄) 和 /boot 兩個路徑下是否有extlinux.conf文件,如果找到這個文件就會去執行boot_extlinux。

scan_dev_for_extlinux=
	if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${boot_syslinux_conf}; then     
    (/extlinux/extlinux.conf    /boot/extlinux/extlinux.conf)
		echo Found ${prefix}${boot_syslinux_conf}; 
		run boot_extlinux; 
		echo SCRIPT FAILED: continuing...; 
	fi

boot_extlinux=
	sysboot ${devtype} ${devnum}:${distro_bootpart} any ${scriptaddr} ${prefix}${boot_syslinux_conf}
	---> sysboot mmc 0:4 any  0xc4100000   (/extlinux/extlinux.conf    /boot/extlinux/extlinux.conf)

scan_dev_for_scripts是去尋找SD卡boot分區裡面是否有boot.scr.uimg和boot.scr檔案,假如有的話就會執行boot_a_script

scan_dev_for_scripts=
	for script in ${boot_scripts};                                       
	do 
		if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${script}; then       # mmc 0:4 (/boot.scr.uimg  /boot.scr  /boot/boot.scr.uimg  /boot/boot.scr)
			echo Found U-Boot script ${prefix}${script}; 
			run boot_a_script; 
			echo SCRIPT FAILED: continuing...; 
		fi; 
	done

boot_a_script=
	load ${devtype} ${devnum}:${distro_bootpart} ${scriptaddr} ${prefix}${script}; source ${scriptaddr}
		---> load mmc 0:4 0xc4100000 (/boot.scr.uimg  /boot.scr  /boot/boot.scr.uimg  /boot/boot.scr)
		---> source 0xc4100000

boot.scr.uimg 是一個script, st 在yocto裡有說明boot.scr.uimg可以用mkimage來編譯出來。但通常會自己生成,這部份我們不用自己做。

他的流程大概如下:

  1. 設定環境變數來啟動M4 Kernel
  2. 尋找bootfs分割區下面的extlinux.conf 來選擇特定的啟動設定,像是設備樹、Image 檔案等等。

修改DDR大小

memory@80000000 {
		device_type = "memory";
		reg = <0x0 0x80000000 0x0 0x80000000>;
	};

舉個例子,如果說你想要在這邊使用某個 button 的功能,那可以像下方這樣去做設定。

/*
	gpio-keys {
		compatible = "gpio-keys";

		button-user-1 {
			label = "User-1";
			linux,code = <BTN_1>;
			gpios = <&gpiod 5 GPIO_ACTIVE_HIGH>;
			status = "okay";
		};

		button-user-2 {
			label = "User-2";
			linux,code = <BTN_2>;
			gpios = <&gpiog 2 GPIO_ACTIVE_HIGH>;
			status = "okay";
		};

		button-wake-up {
			label = "wake-up";
			linux,code = <KEY_WAKEUP>;
			interrupts-extended = <&optee 0>;
			status = "okay";
		};
	}; */

在當中的gpios就可以去修改為對應的腳位。
以及 GPIO_ACTIVE_HIGH 或者是 GPIO_ACTIVE_LOW,當我們設定成 GPIO_ACTIVE_HIGH 表示在高電位的時候觸發他的功能 (高電位有效),相反的 GPIO_ACTIVE_LOW 也就是低電位有效。

接著與啟動息息相關的就是 SD 卡與 emmc , 我們可以在設備樹當中找到 sdemmc1 , sdemmc1 。 分別對應的會是 SD 卡與 emmc , 假如想要修改的話可以找到像下方的段落,按照對應的屬性去修改。這邊推薦可以看看 ST 官方的 develop package , 當中會有非常多的 yaml檔用來說明dts的屬性有哪些,以及該如何用。

&sdmmc1 {
	pinctrl-names = "default", "opendrain", "sleep";
	pinctrl-0 = <&sdmmc1_b4_pins_a>;
	pinctrl-1 = <&sdmmc1_b4_od_pins_a>;
	pinctrl-2 = <&sdmmc1_b4_sleep_pins_a>;
	cd-gpios = <&gpiof 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
	disable-wp;
	st,neg-edge;
	bus-width = <4>;
	vmmc-supply = <&scmi_vdd_sdcard>;
	vqmmc-supply = <&scmi_vddio1>;
	sd-uhs-sdr12;
	sd-uhs-sdr25;
	sd-uhs-sdr50;
	sd-uhs-ddr50;
	sd-uhs-sdr104; 
	status = "okay";
};

將修改儲存成 patch 檔案

git add . && git commit -m "test"
devtool finish u-boot-stm32mp /home/ubuntu/stm32mp1/layers/meta-custom # 依照個人修改

編譯

bitbake u-boot-stm32mp

上一篇
Day 22 。初入嵌入式開發- 如何修改 BSP - Optee 篇
下一篇
Day 24 。初入嵌入式開發- 如何修改 BSP - Kernel 篇
系列文
門外漢的嵌入式地獄30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言